#include "SwfUI.h"
#include "EventHandler.h"
#include "FlashContainer.h"

namespace SwfUI
{
	namespace detail
	{
		void createFlashObject(ShockwaveFlashObjects::IShockwaveFlash** handle);
		const std::wstring& getBaseDir();

		int mouseMsg[] = 
		{
			WM_LBUTTONUP,
			WM_LBUTTONDOWN,
			WM_RBUTTONUP,
			WM_RBUTTONDOWN,
			WM_MBUTTONUP,
			WM_MBUTTONDOWN,
			WM_MOUSEMOVE,
			WM_MOUSEWHEEL
		};

		int mouseWparam[] =
		{
			0,
			MK_LBUTTON,
			0,
			MK_RBUTTON,
			0,
			MK_MBUTTON,
			0,
			0
		};

		const wchar_t* renderQualities[]=
		{
			L"low",
			L"medium",
			L"high",
			L"best",
			L"autolow",
			L"autohigh"
		};
	}

	extern Control* focusedControl;

	Control::Control(int width, int height)
		:width(width),height(height)
	{
		detail::createFlashObject(&flashObject);

		container = new detail::FlashContainer(this);
		container->AddRef();
		eventHandler = new detail::EventHandler();
		eventHandler->AddRef();
		eventHandler->Init(this);

		//put flash in container
		IOleObject* oleObject = 0;
		flashObject->QueryInterface(&oleObject);
		oleObject->SetClientSite(container);
		
		//adjust size
		IOleInPlaceObject* inPlaceObject = 0;	
		oleObject->QueryInterface(&inPlaceObject);			

		if(inPlaceObject)
		{
			RECT rect;
			rect.top = 0;
			rect.left = 0;
			rect.right = width;
			rect.bottom = height;
			inPlaceObject->SetObjectRects(&rect, &rect);
			inPlaceObject->Release();
		}

		flashObject->WMode = L"transparent";
		flashObject->DisableLocalSecurity();

		oleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, 0, container, 0, 0, 0);
		oleObject->QueryInterface(&windowlessObj);
		oleObject->Release();
	}

	void Control::load(const std::wstring& swfFile)
	{
		std::wstring fullPath = detail::getBaseDir() + swfFile;
		flashObject->Movie=fullPath.c_str();
		flashObject->Play();
	}

	Control::~Control()
	{
		if(this == focusedControl)
			setFocus(0);

		IOleObject* oleObject = 0;
		flashObject->QueryInterface(&oleObject);
		oleObject->Close(OLECLOSE_NOSAVE);
		oleObject->Release();

		eventHandler->Shutdown();
		eventHandler->Release();
		windowlessObj->Release();
		flashObject->Release();	
		container->Release();
	}

	void Control::injectMouse(MouseEventType type, int x, int y, int wheel)
	{
		transformToLocal(x,y);
		if( x < 0 || y <0 || x > width || y > height)
			return;

		LRESULT result;
		WPARAM wParam = detail::mouseWparam[type];
		LPARAM lParam = MAKELPARAM(x,y);

		if(type==MET_MOUSEWHEEL)
			wParam = MAKEWPARAM(0,wheel);

		HRESULT res=windowlessObj->OnWindowMessage(detail::mouseMsg[type],wParam,lParam,&result);
	}

	void Control::injectKey(void* msg)
	{
		MSG* _msg = (MSG*) msg;
		LRESULT result;
		windowlessObj->OnWindowMessage(_msg->message,_msg->wParam,_msg->lParam,&result);
	}

	void Control::setRenderQuality(RenderQuality quality)
	{
		flashObject->Quality2 = detail::renderQualities[quality];
	}

	bool Control::isPointInControl(int x, int y) const
	{
		transformToLocal(x,y);		

		if( x < 0 || y <0 || x > width || y > height)
			return false;
		return true;
	}	

	void Control::setTransparent(bool transparent)
	{
		this->transparent = transparent;
		if(transparent)
			flashObject->WMode = L"transparent";
		else
			flashObject->WMode = L"opaque";
	}

	Argument Control::callFunction(const std::wstring& functionName, const ArgumentList& args)
	{
		std::wstring invocation;
		detail::serializeInvocation(functionName,args,invocation);
		std::wstring result = (wchar_t*)flashObject->CallFunction(invocation.c_str());
		return detail::deserializeValue(result);
	}

	Argument Control::onFlashCall(const std::wstring& functionName, const ArgumentList& args)
	{
		return Argument::Null;
	}

	void Control::onFSCommand(const wchar_t* command, const wchar_t* args)
	{
	}
}